package com.yuanzhy.tools.commons.httpclient;

import org.apache.commons.io.IOUtils;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.HttpVersion;
import org.apache.hc.core5.http.Method;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.junit.Test;

import static com.yuanzhy.tools.commons.Util.println;

public class V5 {

    public void t5() {
        // httpClient对象是线程安全的，可以单例使用，提升性能
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost("https://test.com/");
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(Timeout.ofSeconds(2))
                .setConnectionRequestTimeout(Timeout.ofSeconds(2))
                .setResponseTimeout(Timeout.ofSeconds(2))
                .build();
        httpPost.setConfig(requestConfig);
        httpPost.setVersion(HttpVersion.HTTP_2); // 支持http2

        httpPost.setHeader("Content-Type", "application/json");
        // 支持多种entity参数，字节数组，流，文件等等
        // 此处使用restful的"application/json"，所以传递json字符串
//        httpPost.setEntity(new StringEntity(JSON.toJSONString(paramsObj)));
        try (CloseableHttpResponse res = httpClient.execute(httpPost)) {
            if (res.getCode() == HttpStatus.SC_OK) {
                HttpEntity entity = res.getEntity();
                println(EntityUtils.toString(entity));
            } else {
                System.err.println("请求失败，状态码：" + res.getCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放连接资源
            httpPost.reset();
        }
    }
    // 一种用于确定是否应将 HTTP 请求重定向到新位置以响应从目标服务器收到的 HTTP 响应的策略。
    // 该接口的实现必须是线程安全的。对共享数据的访问必须同步，因为该接口的方法可以从多个线程执行。
    public void redirect() {
        CloseableHttpClient httpClient = HttpClients.custom()
                .disableAutomaticRetries() //关闭自动重试
                .setRedirectStrategy(DefaultRedirectStrategy.INSTANCE)
                .build();
        // ... ...
    }

    @Test
    public void async() {
        CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
        SimpleHttpRequest request = SimpleHttpRequest.create(Method.GET.name(), "https://www.baidu.com/");
        httpClient.start();
        httpClient.execute(request, new FutureCallback<SimpleHttpResponse>() {
            @Override
            public void completed(SimpleHttpResponse result) {
                // 响应成功
                println(result.getBodyText());
                IOUtils.closeQuietly(httpClient);
            }

            @Override
            public void failed(Exception ex) {
                // 响应出错
                ex.printStackTrace();
                IOUtils.closeQuietly(httpClient);
            }

            @Override
            public void cancelled() {
                // 响应取消
                println("cancelled");
                IOUtils.closeQuietly(httpClient);
            }
        });
        // ... ... 做其他业务处理

        // 此处为了防止程序退出
        // 实际业务场景此处应去处理其他业务逻辑
        try {
            httpClient.awaitShutdown(TimeValue.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
